/*******************************************************************************
Jimm - Mobile Messaging - J2ME ICQ clone
Copyright (C) 2003-04  Jimm Project

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
********************************************************************************
File: src/jimm/comm/SearchAction.java
 Version: ###VERSION###  Date: ###DATE###
Author(s): Andreas Rossbacher
*******************************************************************************/

// #sijapp cond.if protocols_ICQ is "true" #
package protocol.icq.action;

import jimm.*;
import jimm.comm.*;
import protocol.icq.packet.*;
import jimm.search.*;


public class SearchAction extends IcqAction {
    
    // States of search mission
    public static final int STATE_ERROR                  = -1;
    public static final int STATE_UIN_SEARCH_SENT        = 1;
    public static final int STATE_EMAIL_SEARCH_SENT      = 2;
    public static final int STATE_WHITEPAGES_SEARCH_SENT = 3;
    public static final int STATE_FIRSTRESULT_RECEIVED   = 4;
    public static final int STATE_LASTRESULT_RECEIVED    = 5;
    public static final int STATE_SEARCH_FINISHED        = 6;
    public static final int STATE_SEARCH_CANCELED        = 7;
    
    // TLVs used in LE format
    public static final int TLV_TYPE_UIN                 = 0x3601; // long (4 byte)
    public static final int TLV_TYPE_NICK                = 0x5401; // String (2 byte length + string)
    public static final int TLV_TYPE_FIRSTNAME           = 0x4001; // String (2 byte length + string)
    public static final int TLV_TYPE_LASTNAME            = 0x4A01; // String (2 byte length + string)
    public static final int TLV_TYPE_EMAIL               = 0x5E01; // String (2 byte length + string + 1 byte email code)
    public static final int TLV_TYPE_CITY                = 0x9001; // String (2 byte length + string)
    public static final int TLV_TYPE_KEYWORD             = 0x2602; // String (2 byte length + string)
    public static final int TLV_TYPE_GENDER              = 0x7C01; // UINT8 (1 byte: 1 - female, 2 - male)
    public static final int TLV_TYPE_ONLYONLINE          = 0x3002; // UINT8 (1 byte:  1 - search online, 0 - search all)
    public static final int TLV_TYPE_AGE                 = 0x6801; // 
    
    
    // Search action was called by
    public static final int CALLED_BY_SEARCHUSER         = 0;
    public static final int CALLED_BY_ADDUSER            = 1;
    
    // Timeout
    public static final int TIMEOUT = 60 * 1000; // milliseconds
    
    /****************************************************************************/

    // Action state
    private int state;
    
    // Search object as container for request and results
    private Search cont;
    
    // Last activity
    private long lastActivity = System.currentTimeMillis();
    
    public SearchAction(Search cont) {
    	super();
    	this.cont = cont;
    }

    private void addStr(Util buffer, int tlv, int param) {
        String str = cont.getSearchParam(param);
        if (null != str) {
            buffer.writeAsciizTLV(tlv, str);
        }
    }
    // Init action
    public void init() throws JimmException {
        Util buffer = new Util();
        
        buffer.writeWordBE(0x5f05);

        // UIN
        int uin = Util.strToIntDef(cont.getSearchParam(Search.UIN), 0);
        if (uin != 0) {
            buffer.writeWordBE(TLV_TYPE_UIN);
            buffer.writeWordLE(0x0004);
            buffer.writeDWordLE(uin);
        }
        
        addStr(buffer, TLV_TYPE_NICK, Search.NICK);
        addStr(buffer, TLV_TYPE_FIRSTNAME, Search.FIRST_NAME);
        addStr(buffer, TLV_TYPE_LASTNAME, Search.LAST_NAME);
        addStr(buffer, TLV_TYPE_EMAIL, Search.EMAIL);
        addStr(buffer, TLV_TYPE_CITY, Search.CITY);
        addStr(buffer, TLV_TYPE_KEYWORD, Search.KEYWORD);
        
        // Age (user enter age as "minAge-maxAge", "-maxAge", "minAge-")
        String[] age = Util.explode(cont.getSearchParam(Search.AGE), '-');
        if ((age.length == 2) && ((age[0].length() > 0) || (age[1].length() > 0))) {
            buffer.writeWordBE(0x6801);
            buffer.writeWordLE(4);
            buffer.writeWordLE(Util.strToIntDef(age[0], 0));
            buffer.writeWordLE(Util.strToIntDef(age[1], 99));
        }
        
        
        // Gender
        int gender = Util.strToIntDef(cont.getSearchParam(Search.GENDER), 0);
        if (gender != 0) {
            buffer.writeWordBE(TLV_TYPE_GENDER);
            buffer.writeWordLE(1);
            buffer.writeByte(gender);
        }
        
        // Only online
        buffer.writeWordBE(TLV_TYPE_ONLYONLINE);
        buffer.writeWordLE(1);
        buffer.writeByte(("1".equals(cont.getSearchParam(Search.ONLY_ONLINE))) ? 1 : 0);
        
        sendPacket(new ToIcqSrvPacket(SnacPacket.CLI_TOICQSRV_COMMAND,
                0x0002, getIcq().getUserId(), 0x07D0, new byte[0], buffer.toByteArray()));
        
        this.state = STATE_UIN_SEARCH_SENT;
    }
    

    // Forwards received packet, returns true if packet was consumed
    public boolean forward(Packet packet) throws JimmException {
        // Flag indicates whether packet has been consumed or not
        boolean consumed = false;
        if (this.state == STATE_UIN_SEARCH_SENT || this.state == STATE_FIRSTRESULT_RECEIVED) {
            // Watch out for SRV_FROMICQSRV packet type
            if (packet instanceof FromIcqSrvPacket) {
                FromIcqSrvPacket fromIcqServerPacket = (FromIcqSrvPacket) packet;
                UserInfo info = new UserInfo(getIcq());
                                
                
                int marker = 0;
                
                byte[] data = fromIcqServerPacket.getData();
                
                if (Util.getWordBE(data,marker) == 0xa401) {
                    this.state = STATE_FIRSTRESULT_RECEIVED;
                } else if (Util.getWordBE(data,marker) == 0xae01) {
                    this.state = STATE_LASTRESULT_RECEIVED;
                }
                
                marker += 2;
                if (Util.getByte(data,marker)== 0x0A) {
                    // Get UIN
                    marker += 3;
                    long uin = Util.getDWordLE(data, marker);
                    info.uin = String.valueOf(uin);

                    // Get nick
                    marker += 4;
                    
                    String[] strings = new String[4];
                    
                    // Get the strings
                    // #0 Nick
                    // #1 Firstname
                    // #2 Lastname
                    // #3 EMail
                    for (int i = 0; i < 4; ++i) {
                        int len = Util.getWordLE(data, marker);
                        strings[i] = StringConvertor.byteArrayToWinString(data, marker + 2, len);
                        marker += 2 + len;
                    }
                    info.nick      = strings[0];
                    info.firstName = strings[1];
                    info.lastName  = strings[2];
                    info.email     = strings[3];
                    
                    // Get auth flag
                    info.auth = (Util.getByte(data, marker) == 0);
                    marker += 1;
                    
                    // Get status
                    int status = Util.getWordLE(data, marker);
                    info.status = Integer.toString(status);
                    marker += 2;
                    
                    // Get gender
                    info.gender = (byte)Util.getByte(data, marker);
                    marker += 1;
                    
                    // Get age
                    info.age = Util.getWordLE(data, marker);
                    cont.addResult(info);
                    if (this.state == STATE_LASTRESULT_RECEIVED) {
                        marker += 2;
                        long foundleft = Util.getDWordLE(data, marker);
                        this.state = STATE_SEARCH_FINISHED;
                        cont.finished();
                    }
                } else {
                    this.state = ConnectAction.STATE_ERROR;
                }
            }
        }
        
        // Update activity timestamp
        this.lastActivity = System.currentTimeMillis();
        
        return consumed;
    }
        
    // Returns true if the action is completed
    public boolean isCompleted() {
        return (state == STATE_SEARCH_FINISHED)
                || (state == STATE_SEARCH_CANCELED);
    }

    // Returns true if an error has occured
    public boolean isError() {
        return (state == ConnectAction.STATE_ERROR) || 
        		((lastActivity + TIMEOUT) < System.currentTimeMillis());
    }
}
// #sijapp cond.end #
